package Connector;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Vector;

import Components.RoomsPanel;
import server.StateOfGame;
import smash_tris.*;

/**
 * Klasa reprezentuje połączenie pomiędzy klientem a serwerem.
 * 
 * @author Maciej Graszek
 * @author Pawel Rychly
 * 
 */
public class Connector /* implements Runnable */{

	private Socket clientSocket = null;
	private Socket broadcastMessagesSocket = null;

	private ObjectInputStream in = null;
	private ObjectOutputStream out = null;
	private ObjectInputStream broadCastIn = null;
	// private ObjectOutputStream broadCastOut = null;

	private String adres = "localhost";
	private boolean isRunning = false;

	private int portNumber = 3001;
	private int broadCastPortNumber = portNumber + 1;
	private InetAddress adr;
	private Player player = null;

	private RoomsPanel roomsPanel = null;

	public Connector() throws IOException {

		try {
			clientSocket = new Socket(adr.getLocalHost(), portNumber);
			System.out.println("połączono");
			this.broadcastMessagesSocket = new Socket(adr.getLocalHost(),
					broadCastPortNumber);
			System.out.println("połączono");
			out = new ObjectOutputStream(new BufferedOutputStream(
					clientSocket.getOutputStream()));
			out.flush();

			in = new ObjectInputStream(new BufferedInputStream(
					clientSocket.getInputStream()));

			System.out.println("socket ok");

			broadCastIn = new ObjectInputStream(new BufferedInputStream(
					broadcastMessagesSocket.getInputStream()));
			System.out.println("broad cast socket ok");

		} catch (UnknownHostException e) {
			System.err.println("Don't know about host: localhost.");
			System.exit(1);
		} catch (IOException e) {
			System.err.println("Couldn't get I/O for "
					+ "the connection to: taranis.");
			System.exit(1);
		}

		/*
		 * Thread t = new Thread(this); this.isRunning = true; t.start();
		 */
		/*
		 * BufferedReader stdIn = new BufferedReader( new
		 * InputStreamReader(System.in));
		 */
	}

	/*
	 * @Override public void run() { DataPacket userInput; while (isRunning) {
	 * try { while ((userInput = (DataPacket) in.readObject()) != null) {
	 * System.out.println(userInput.getTypeOfInformation());
	 * System.out.println("wyświetlono"); } } catch (ClassNotFoundException e) {
	 * // TODO Auto-generated catch block e.printStackTrace(); } catch
	 * (IOException e) { // TODO Auto-generated catch block e.printStackTrace();
	 * } }
	 * 
	 * }
	 */

	/**
	 * Metoda zwraca obiekt reprezentujący Strumień danych pochodzących z
	 * broadcast socketa.
	 * 
	 * @return ObjectOutputStream - obiekt reprezentujący strumień danych z
	 *         broadcast socketa.
	 */
	public ObjectInputStream getBroadCastIn() {
		return this.broadCastIn;
	}

	/**
	 * Metoda zwraca listę wszystkich pokoi gry, odebraną z serwera.
	 * 
	 * @return Lista pokoi gry.
	 */
	public Vector<Room> getAllRooms() {
		Vector<Room> rooms = null;
		try {
			this.out.writeObject(new DataPacket(
					TypeOfDataPacket.GET_LIST_OF_ROOMS, null));
			this.out.flush();

			DataPacket userInput = null;
			userInput = (DataPacket) in.readObject();
			rooms = (Vector<Room>) userInput.getData();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return rooms;
	}

	/**
	 * Metoda tworzy nowy pokój.
	 * 
	 * @param nick
	 * @return
	 */
	public Player createPlayer(String nick) {
		System.out.println("nick: " + nick);
		Player playerT = null;
		try {
			this.out.writeObject(new DataPacket(TypeOfDataPacket.ADD_PLAYER,
					nick));
			this.out.flush();
			DataPacket userInput = null;
			userInput = (DataPacket) in.readObject();
			playerT = (Player) userInput.getData();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.player = playerT;
		System.out.println(this.player.getNick());
		return player;
	}

	/**
	 * Wysyła do serwera żądanie utworzenia nowego pokoju.
	 * 
	 * @return Aktualna lista pokoi.
	 */
	@SuppressWarnings("unchecked")
	public Room createRoom(String name) {
		/*try {
			in.reset();
		} catch (IOException e1) {
			System.out.println("error___________");
		}*/
		System.out.println("createRoom");
		Room room = null;
		if (this.player != null) {
			//room = new Room(this.player, name);
			try {
				System.out.println("WRITE SENDING ADD ROOM");
				this.out.writeObject(new DataPacket(TypeOfDataPacket.ADD_ROOM,
						name));
				this.out.flush();
				
				
				
				DataPacket userInput = null;
				System.out.println("wait...");
				userInput = (DataPacket) in.readObject();
				
				System.out.println("RESPONSE SENDING ADD ROOM");
				System.out.println("RESPONSE___");
				if (userInput.getTypeOfInformation() == TypeOfDataPacket.RESPONSE_OK) {
					System.out.println("Response_OK");
					room = (Room) userInput.getData();
				} else {
					System.out.println("Response_ERROR");
					return null;
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		return room;

	}

	/**
	 * Kończy działanie connectora.
	 */
	public void close() {
		this.isRunning = false;
		System.out.println("koniec");
		try {
			DataPacket dataPacket = new DataPacket(
					TypeOfDataPacket.REMOVE_PLAYER, this.player);
			out.writeObject(dataPacket);
			out.flush();
			System.out.println("koniec");

			synchronized (out) {
				out.close();
				in.close();
				clientSocket.close();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * Metoda dodaje gracza do pokoju gry
	 * 
	 * @param room
	 * @return
	 */
	public boolean addPlayerToRoom(Room room) {
		DataPacket dataPacket = new DataPacket(TypeOfDataPacket.JOIN_TO_ROOM,
				room);

		try {
			out.writeObject(dataPacket);
			out.flush();
			
			out.reset();
			//in.reset();
			
			dataPacket = (DataPacket) in.readObject();
			if (dataPacket.getTypeOfInformation() == TypeOfDataPacket.RESPONSE_OK) {
				return true;
			} else {
				return false;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * Metoda przypisuje referencje do obiektu RoomsPanel.
	 * 
	 * @param roomsPanel
	 */
	public void setRoomsPanel(RoomsPanel roomsPanel) {
		this.roomsPanel = roomsPanel;
	}

	/*
	 * public void sendStateOfGame(StateOfGame state){ DataPacket dataPacket =
	 * new DataPacket( TypeOfDataPacket.STATE_OF_GAME, state);
	 * 
	 * try { out.writeObject(dataPacket); out.flush();
	 * 
	 * dataPacket = (DataPacket) in.readObject();
	 * 
	 * } catch (IOException e) { // TODO Auto-generated catch block
	 * e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO
	 * Auto-generated catch block e.printStackTrace(); } }
	 * 
	 * public StateOfGame getStateOfGame() {
	 * 
	 * }
	 */
	
	public void resetStreams(){
		try {
			this.out.reset();
			//this.in.reset();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println("in.reset");
		}
		
	}
	
	public boolean stopGame(){
		DataPacket dataPacket = null;
		try {
			dataPacket = (DataPacket) in.readObject();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (ClassNotFoundException e1) {
			// TODO Auto-generated catch block
			
			e1.printStackTrace();
		}
		if (dataPacket.getTypeOfInformation() != TypeOfDataPacket.EXIT_FROM_ROOM) {

			try {
				this.out.writeObject(new DataPacket(TypeOfDataPacket.EXIT_FROM_ROOM));
				this.out.flush();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		return true;
	}
	
	public DataPacket play(StateOfGame state)
			throws IOException, ClassNotFoundException {
		System.out.println("PLAY!!");
		
		
			DataPacket sendPacket = new DataPacket(
					TypeOfDataPacket.STATE_OF_GAME, state);

			
			DataPacket dataPacket = (DataPacket) in.readObject();
			System.out.println("PLAY!!!!");
			if (dataPacket.getTypeOfInformation() == TypeOfDataPacket.STATE_OF_GAME) {
				this.out.writeObject(sendPacket);
				this.out.flush();
			} else if (dataPacket.getTypeOfInformation() == TypeOfDataPacket.START_GAME) {
				this.out.writeObject(sendPacket);
				this.out.flush();
			} else if (dataPacket.getTypeOfInformation() == TypeOfDataPacket.EXIT_FROM_ROOM) {
				this.out.writeObject(new DataPacket(TypeOfDataPacket.RESPONSE_OK));
				this.out.flush();
			}
			System.out.println(dataPacket.getTypeOfInformation().toString());
		

		return dataPacket;
	}

	public boolean isGameStarted() {

		try {
			DataPacket data = (DataPacket) in.readObject();
			if (data.getTypeOfInformation() == TypeOfDataPacket.START_GAME) {
				return true;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}

	public Integer setReady(Room room) {
		DataPacket data = null;
		try {
			this.out.writeObject(new DataPacket(TypeOfDataPacket.SET_READY,
					room));
			this.out.flush();
			data = (DataPacket) this.in.readObject();

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		if ((data != null)
				&& (data.getTypeOfInformation() == TypeOfDataPacket.RESPONSE_OK)) {
			return (Integer) data.getData();
		} else {
			return 0;
		}
	}

	public void setStart() {
		DataPacket dataPacket = new DataPacket(TypeOfDataPacket.SET_START, null);

		try {
			out.writeObject(dataPacket);
			out.flush();

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	
	public Room getRoom(Room room) {
		DataPacket data = null;
		try {
			this.out.writeObject(new DataPacket(TypeOfDataPacket.GET_ROOM, room));
			this.out.flush();
			data = (DataPacket) this.in.readObject();
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		if ((data != null) && 
				(data.getTypeOfInformation() == TypeOfDataPacket.RESPONSE_OK)) {
			return (Room) data.getData();
		} else {
			return null;
		}
		
	}
	

}

